using System.Collections.Generic;
using System.Linq;

namespace HybridCLR.Extension.Editor
{
    public partial class Commond
    {
        [UnityEditor.MenuItem("HybridCLR/Extension/CopyAotDllToPath_Test")]
        public static void CopyAotDllToPath_Test()
        {
            CopyAotDllToPath();
        }

        public static void CopyAotDllToPath(BuildParam buildParam)
        {
            CopyAotDllToPath(buildParam.CopyDllToPath);
        }
        public static void CopyAotDllToPath(string copyToPath = "Assets/HybridCLRGenerate/Dll")
        {
            if(!System.IO.Directory.Exists(copyToPath))
                System.IO.Directory.CreateDirectory(copyToPath);
            var list = _GenerateAOTGenericReference();
            AotDllConfig config = new AotDllConfig();
            foreach (var e in list)
            {
                string oldFilePath = System.IO.Path.Combine(HybridCLR.Editor.SettingsUtil.GetAssembliesPostIl2CppStripDir(UnityEditor.EditorUserBuildSettings.activeBuildTarget), e);
                string newFilePath = System.IO.Path.Combine(copyToPath, e + ".bytes");
                System.IO.File.Copy(oldFilePath, newFilePath, true);
                config.patchAot.Add(e.Replace(".dll", ""));
            }

            string targetPath = System.IO.Path.Combine(copyToPath, "AotDllConfig.json");
            string oldFileContent = null;
            if (System.IO.File.Exists(targetPath))
            {
                oldFileContent = System.IO.File.ReadAllText(targetPath);
            }
            string jsonContent = UnityEngine.JsonUtility.ToJson(config);
            System.IO.File.WriteAllText(targetPath, jsonContent);
            UnityEditor.AssetDatabase.SaveAssets();
            UnityEditor.AssetDatabase.Refresh();
            if (oldFileContent != jsonContent)
            {
                UnityEditor.EditorUtility.DisplayDialog("CopyAotDllToPath", "补充元数据Dll有变化, 请注意将新增的Dll加入资源构建中", "确定");
            }
        }
        
        /// <summary>
        /// 计算热更代码中的泛型引用
        /// </summary>
        /// <param name="target"></param>
        private static List<string> _GenerateAOTGenericReference()
        {
            UnityEditor.BuildTarget target = UnityEditor.EditorUserBuildSettings.activeBuildTarget;
            HybridCLR.Editor.Commands.CompileDllCommand.CompileDll(target);
            
            var gs = HybridCLR.Editor.SettingsUtil.HybridCLRSettings;
            List<string> hotUpdateDllNames = HybridCLR.Editor.SettingsUtil.HotUpdateAssemblyNamesExcludePreserved;

            HybridCLR.Editor.Meta.AssemblyReferenceDeepCollector collector = new HybridCLR.Editor.Meta.AssemblyReferenceDeepCollector(HybridCLR.Editor.Meta.MetaUtil.CreateHotUpdateAndAOTAssemblyResolver(target, hotUpdateDllNames), hotUpdateDllNames);
            var analyzer = new HybridCLR.Editor.AOT.Analyzer(new HybridCLR.Editor.AOT.Analyzer.Options
            {
                MaxIterationCount = System.Math.Min(20, gs.maxGenericReferenceIteration),
                Collector = collector,
            });

            analyzer.Run();
            var types = analyzer.AotGenericTypes.ToList();
            var methods = analyzer.AotGenericMethods.ToList();
            List<dnlib.DotNet.ModuleDef> modules = new HashSet<dnlib.DotNet.ModuleDef>(
                types.Select(t => t.Type.Module).Concat(methods.Select(m => m.Method.Module))).ToList();
            modules.Sort((a, b) => a.Name.CompareTo(b.Name));
            List<string> dlls = new List<string>();
            foreach (dnlib.DotNet.ModuleDef module in modules)
            {
                dlls.Add(module.Name);
            }
            return dlls;
        }

        
    }
}
